package com.mb.app.service.impl;

import com.mb.app.bo.ChannelPvUvBO;
import com.mb.app.dao.IChannelPvUvMapper;
import com.mb.app.dao.TbChannelConfigMapper;
import com.mb.app.dao.TbReportChannelMapper;
import com.mb.app.domain.TbChannelConfig;
import com.mb.app.domain.TbReportChannel;
import com.mb.app.service.IChannelPvUvService;
import com.mb.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * 渠道PVUV跑批服务实现
 * @author liliping
 * @create 2019-03-27 2:08 PM
 **/
@Service("channelPvUvService")
@Slf4j
public class ChannelPvUvServiceImpl implements IChannelPvUvService {

    @Autowired
    private IChannelPvUvMapper channelPvUvMapper;

    @Autowired
    private TbReportChannelMapper reportChannelMapper;

    @Autowired
    private TbChannelConfigMapper channelConfigMapper;


    @Override
    public int runReport() {
        String reportDate = DateUtils.format(new Date(),"yyyy-MM-dd");

        List<ChannelPvUvBO> list = channelPvUvMapper.getAppInfo();
        if(list != null && list.size() != 0){
            Iterator<ChannelPvUvBO> it = list.iterator();
            while (it.hasNext()){
                ChannelPvUvBO channelPvUvBO = it.next();
                Long appId = channelPvUvBO.getAppId();
                Long channelId = channelPvUvBO.getChannelId();

                try {
                    runSingle(reportDate, appId, channelId);
                    log.info("ChannelPvUv run end.");
                } catch (Exception e) {
                    log.error("runReport Exception",e);
                }
            }
        }
        return 1;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public int runSingleByDate(String reportDate) {

        List<ChannelPvUvBO> list = channelPvUvMapper.getAppInfo();
        if(list != null && list.size() != 0){
            Iterator<ChannelPvUvBO> it = list.iterator();
            while (it.hasNext()){
                ChannelPvUvBO channelPvUvBO = it.next();
                Long appId = channelPvUvBO.getAppId();
                Long channelId = channelPvUvBO.getChannelId();

                try {
                    runSingle(reportDate, appId, channelId);
                    log.info("ChannelPvUv run end.");
                } catch (Exception e) {
                    log.error("runReport Exception",e);
                }
            }
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void runSingle(String reportDate, Long appId, Long channelId) {
        log.info("ChannelPvUv runSingle ,reportDate :"+reportDate +", appId :"+appId +",channelId :"+channelId);
        //delete
        Map<String,Object> delMap = new HashMap<>();
        delMap.put("report_date",reportDate);
        delMap.put("app_id",appId);
        delMap.put("channel_id",channelId);
        reportChannelMapper.deleteByMap(delMap);

        Map<String, Object> map = new HashMap<>();
        map.put("reportDate",reportDate);
        map.put("appId",appId);
        map.put("channelId",channelId);

        //渠道点击pv
        Integer pv = channelPvUvMapper.getPv(map);

        //渠道点击uv
        Integer uv = this.getUv(map);
        //当日注册量
        Integer todayRegCount = this.getTodayRegCount(map);
        //UV转化率
        BigDecimal uvConvertRate = this.getUvConvertRate(todayRegCount,uv);
        //存量用户
        //1. 今天从本渠道渠道进来的，注册日期为非今天的为存量用户（不管是注册在了那个渠道下面）
        //2. 今天本渠道的点击用户，注册日期为今天的其他渠道用户也算存量用户
        Integer regCount = this.getRegCount(map);
        //反馈用户
        Integer feedbackCount = this.getFeedbackCount(todayRegCount,channelId);
        //反馈UV转化率
        BigDecimal uvFeedbackConvertRate = this.getUvFeedbackConvertRate(feedbackCount,uv);
        //登录成功
        Integer loginCount = this.getLoginCount(map);
        //登录转化率
        BigDecimal loginConvertRate = this.getLoginConvertRate(loginCount,todayRegCount);
        //点击人数
        Integer userClickCount = this.getUserClickCount(map);
        //点击人数占比 点击人数/注册用户
        BigDecimal clickRate = this.getClickRate(userClickCount,todayRegCount);
        //点击次数
        Integer clickTimes = this.getClickTimes(map);
        //老用户点击人数
        Integer oldUserClickCount = this.getOldUserClickCount(map);
        //老用户点击次数
        Integer oldUserClickTimes = this.getOldUserClickTimes(map);
        //人均点击次数 点击次数/反馈用户
        BigDecimal avgClickTimes = this.getAvgClickTimes(clickTimes,feedbackCount);

        TbReportChannel reportChannel = new TbReportChannel();
        reportChannel.setReportDate(reportDate);
        reportChannel.setAppId(appId);
        reportChannel.setChannelId(channelId);

        reportChannel.setPv(pv);
        reportChannel.setUv(uv);
        reportChannel.setTodayRegCount(todayRegCount);
        reportChannel.setUvConvertRate(uvConvertRate);
        reportChannel.setRegCount(regCount);
        reportChannel.setFeedbackCount(feedbackCount);
        reportChannel.setUvFeedbackConvertRate(uvFeedbackConvertRate);
        reportChannel.setLoginCount(loginCount);
        reportChannel.setLoginConvertRate(loginConvertRate);
        reportChannel.setUserClickCount(userClickCount);
        reportChannel.setClickRate(clickRate);
        reportChannel.setClickTimes(clickTimes);
        reportChannel.setOldUserClickCount(oldUserClickCount);
        reportChannel.setOldUserClickTimes(oldUserClickTimes);
        reportChannel.setAvgClickTimes(avgClickTimes);

        reportChannelMapper.insert(reportChannel);
    }

    private Integer getUv(Map<String,Object> map){
        return channelPvUvMapper.getUv(map);
    }

    private Integer getTodayRegCount(Map<String,Object> map){
        return channelPvUvMapper.getTodayRegCount(map);
    }

    private BigDecimal getUvConvertRate(Integer regCount,Integer uv){
        if(uv == null || uv.intValue() == 0){
            return new BigDecimal(0);
        }
        BigDecimal uvConvertRate = new BigDecimal(regCount)
                .divide(new BigDecimal(uv), 2 ,BigDecimal.ROUND_HALF_DOWN);
        return uvConvertRate;
    }

    private Integer getRegCount(Map<String,Object> map){
        return channelPvUvMapper.getRegCount(map);
    }


    private Integer getFeedbackCount(Integer todayRegCount,Long channelId){
        Integer feedbackCount = 0;
        TbChannelConfig channelConfig = channelConfigMapper.selectById(channelId);
        if(channelConfig != null){
            BigDecimal deductRate = channelConfig.getDeductRate();
            if(deductRate == null || deductRate.compareTo(new BigDecimal(0)) == 0){
                return todayRegCount;
            }
            BigDecimal calRate = new BigDecimal(100).subtract(deductRate);
            calRate = calRate.divide(new BigDecimal(100),2,BigDecimal.ROUND_HALF_DOWN);
            feedbackCount = new Integer(new BigDecimal(todayRegCount).multiply(calRate).intValue());
        }
        return feedbackCount;
    }

    private BigDecimal getUvFeedbackConvertRate(Integer feedbackCount,Integer uv){
        if(uv == null || uv.intValue() == 0){
            return new BigDecimal(0);
        }
        BigDecimal uvFeedbackConvertRate = new BigDecimal(0);
        uvFeedbackConvertRate = new BigDecimal(feedbackCount)
                .divide(new BigDecimal(uv),2,BigDecimal.ROUND_HALF_DOWN);
        return uvFeedbackConvertRate;
    }

    private Integer getLoginCount(Map<String,Object> map){
        return channelPvUvMapper.getLoginCount(map);
    }

        private BigDecimal getLoginConvertRate(Integer loginCount,Integer todayRegCount){
            if(todayRegCount == null || todayRegCount.intValue() == 0){
                return new BigDecimal(0);
            }

        BigDecimal loginConvertRate = new BigDecimal(0);
        loginConvertRate = new BigDecimal(loginCount)
                .divide(new BigDecimal(todayRegCount),2,BigDecimal.ROUND_HALF_DOWN);
        return loginConvertRate;
    }

    private Integer getUserClickCount(Map<String,Object> map){
        return channelPvUvMapper.getUserClickCount(map);
    }

    private BigDecimal getClickRate(Integer clickCount,Integer todayRegCount){
        if(todayRegCount == null || todayRegCount.intValue() == 0){
            return new BigDecimal(0);
        }

        BigDecimal clickRate = new BigDecimal(0);
        clickRate = new BigDecimal(clickCount)
                .divide(new BigDecimal(todayRegCount),2,BigDecimal.ROUND_HALF_DOWN);
        return clickRate;
    }

    public Integer getClickTimes(Map<String,Object> map){
        return channelPvUvMapper.getClickTimes(map);
    }

    public Integer getOldUserClickCount(Map<String,Object> map){
        return channelPvUvMapper.getOldUserClickCount(map);
    }

    public Integer getOldUserClickTimes(Map<String,Object> map){
        return channelPvUvMapper.getOldUserClickTimes(map);
    }

    private BigDecimal getAvgClickTimes(Integer clickTimes,Integer feedbackCount){
        if(feedbackCount == null || feedbackCount.intValue() == 0){
            return new BigDecimal(0);
        }
        BigDecimal avgclickTimes = new BigDecimal(clickTimes)
                .divide(new BigDecimal(feedbackCount),2,BigDecimal.ROUND_UP);
        return avgclickTimes;
    }


}
